﻿using Compass.PlanService.Domain;
using Compass.PlanService.Domain.Entities;
using Compass.Wasm.Shared;
using Microsoft.EntityFrameworkCore;
using Compass.Wasm.Shared.Plans;

namespace Compass.PlanService.Infrastructure;

public class PlanRepository : IPlanRepository
{
    #region ctor
    private readonly PlanDbContext _context;
    public PlanRepository(PlanDbContext context)
    {
        _context = context;
    }
    #endregion

    #region MainPlan
    //MainPlan
    public Task<IQueryable<MainPlan>> GetMainPlansAsync()
    {
        return Task.FromResult(_context.MainPlans.AsQueryable());
    }

    public Task<MainPlan?> GetMainPlanByIdAsync(Guid id)
    {
        return _context.MainPlans.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }
    //扩展查询
    public Task<MainPlan?> GetMainPlanByNumberAsync(string number)
    {
        return _context.MainPlans.SingleOrDefaultAsync(x => x.Number.ToUpper()==number.ToUpper());
    }

    public Task<IQueryable<MainPlan>> GetMainPlansByProjectIdAsync(Guid projectId)
    {
        return Task.FromResult(_context.MainPlans.Where(x => x.IsDeleted==false &&  x.ProjectId.Equals(projectId)).OrderBy(x => x.FinishTime).AsQueryable());
    }

    public Task<MainPlan?> GetMainPlanByProjectIdAndBatchAsync(Guid projectId, int batch)
    {
        return _context.MainPlans
            .SingleOrDefaultAsync(x => x.ProjectId.Equals(projectId)
                                       && x.Batch==batch);
    }

    public Task<List<Guid?>> GetProjectIdsByStatusAsync(MainPlanStatus_e? status)
    {
        var plans = _context.MainPlans.Where(x => x.IsDeleted==false&&  x.Status == status);
        var ids = plans.Select(x => x.ProjectId).ToList();
        return Task.FromResult(ids);
    }
    
    //扩展MainPlan查询
    public double GetDeliveryReliabilityByMonth(int year, int month)
    {
        //筛选今年,截至今天前的项目
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year && 
            x.MonthOfInvoice.Month==month && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0d : GetDeliveryReliability(plans);
    }

    public double GetDeliveryReliabilityByYear(int year)
    {
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0d : GetDeliveryReliability(plans);
    }

    private double GetDeliveryReliability(IQueryable<MainPlan> plans)
    {
        //delivery reliability rate = on time project hoods’ Qty / total hoods’ Qty monthly
        //On time,WarehousingTime<=FinishTime,只比较日期忽略时间部分DateTime.Value.Date
        //去除已经被删除的Pallet,添加判断条件!p.IsDeleted
        //入库日期可以比完工日期晚一天,FinishTime.Date.AddDays(1)
        var onTimePalletsCount = _context.Pallets.Count(p => 
            !p.IsDeleted && 
            p.WarehousingTime!=null && 
            p.WarehousingTime.Value.Date <= plans.Single(m => m.Id == p.MainPlanId).FinishTime.Date.AddDays(1));
        var allPalletsCount = _context.Pallets.Count(p => !p.IsDeleted && plans.Select(m => m.Id).Contains(p.MainPlanId));

        return allPalletsCount==0d? 0d: Math.Round(onTimePalletsCount*100d / allPalletsCount, 2);
    }

    public double GetProductionCycleTimeByMonth(int year, int month)
    {
        //筛选今年,截至今天前的项目
        var plans = _context.MainPlans.Where(x => x.IsDeleted==false && x.MonthOfInvoice.Year==year && x.MonthOfInvoice.Month==month && x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetProductionCycleTime(plans);
    }

    public double GetProductionCycleTimeByYear(int year)
    {
        var plans = _context.MainPlans.Where(x => x.IsDeleted==false && x.MonthOfInvoice.Year==year && x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetProductionCycleTime(plans);
    }
    
    private double GetProductionCycleTime(IQueryable<MainPlan> plans)
    {
        //monthly AVE(finish goods stock in date-drawing released date) 生产周期
        List<int> cycle = new();
        foreach (var plan in plans)
        {
            if (plan.DrwReleaseTime != null && plan.WarehousingTime!=null)
            {
                cycle.Add(plan.WarehousingTime.Value.Subtract(plan.DrwReleaseTime.Value).Days);
            }
        }
        return cycle.Count>0 ? Math.Round(cycle.Average(), 2) : 0.0;
    }

    public double GetFactoryCycleTimeByMonth(int year, int month)
    {
        //筛选今年,截至今天前的项目
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year && 
            x.MonthOfInvoice.Month==month && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetFactoryCycleTime(plans);
    }

    public double GetFactoryCycleTimeByYear(int year)
    {
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetFactoryCycleTime(plans);
    }

    private double GetFactoryCycleTime(IQueryable<MainPlan> plans)
    {
        //monthly AVE(finish goods stock in date-Planning[line creating]date) 工厂周期 
        List<int> cycle = new();
        foreach (var plan in plans)
        {
            if (plan.WarehousingTime!=null)
            {
                cycle.Add(plan.WarehousingTime.Value.Subtract(plan.CreateTime).Days);
            }
        }
        return cycle.Count>0 ? Math.Round(cycle.Average(), 2) : 0.0;
    }

    public double GetOrderCycleTimeByMonth(int year, int month)
    {
        //筛选今年,截至今天前的项目
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year &&
            x.MonthOfInvoice.Month==month && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetOrderCycleTime(plans);
    }

    public double GetOrderCycleTimeByYear(int year)
    {
        var plans = _context.MainPlans.Where(x => 
            x.IsDeleted==false && 
            x.MonthOfInvoice.Year==year && 
            x.FinishTime < DateTime.Now);
        return !plans.Any() ? 0.0 : GetOrderCycleTime(plans);
    }

    private double GetOrderCycleTime(IQueryable<MainPlan> plans)
    {
        //monthly AVE(goods delivered date-Planning[line creating]date) 订单周期
        List<int> cycle = new();
        foreach (var plan in plans)
        {
            if (plan.ShippingTime!=null)
            {
                cycle.Add(plan.ShippingTime.Value.Subtract(plan.CreateTime).Days);
            }
        }
        return cycle.Count>0 ? Math.Round(cycle.Average(), 2) : 0.0;
    }

    //todo:还没设计好
    public CycleTimeDto GetCycleTime(int year)
    {
        CycleTimeDto cycle = new CycleTimeDto();
        //var plans = _context.MainPlans.Where(x => x.IsDeleted==false && x.MonthOfInvoice.Year==year && x.FinishTime < DateTime.Now);



        return cycle;
    }


    #endregion

    #region Issue
    public Task<IQueryable<Issue>> GetIssuesAsync()
    {
        return Task.FromResult(_context.Issues.AsQueryable());
    }

    public Task<Issue?> GetIssueByIdAsync(Guid id)
    {
        return _context.Issues.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }

    public Task<IQueryable<Issue>> GetIssuesByMainPlanIdAsync(Guid mainPlanId)
    {
        return Task.FromResult(_context.Issues.Where(x => 
            x.IsDeleted==false && 
            x.MainPlanId.Equals(mainPlanId)).OrderByDescending(x => x.CreationTime).AsQueryable());
    }

    public Task<IQueryable<Guid>> GetMainPlanIdsByOpenIssueAsync()
    {
        return Task.FromResult(_context.Issues.Where(x => 
            x.IsDeleted==false && 
            x.CloseTime == null ).Select(x => x.MainPlanId ).Distinct());
    }

    #endregion

    #region Lesson
    //基本
    public Task<IQueryable<Lesson>> GetLessonsAsync()
    {
        return Task.FromResult(_context.Lessons.AsQueryable());
    }
    public Task<Lesson?> GetLessonByIdAsync(Guid id)
    {
        return _context.Lessons.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }
    //扩展
    public Task<IQueryable<Lesson>> GetLessonsByMainPlanIdAsync(Guid mainPlanId)
    {
        return Task.FromResult(_context.Lessons.Where(x => 
            x.IsDeleted==false && 
            x.MainPlanId.Equals(mainPlanId)).OrderByDescending(x => x.CreationTime).AsQueryable());
    }
    #endregion

    #region PackingList
    public Task<IQueryable<PackingList>> GetPackingListsAsync()
    {
        return Task.FromResult(_context.PackingLists.AsQueryable());
    }

    public Task<PackingList?> GetPackingListByIdAsync(Guid id)
    {
        return _context.PackingLists.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }

    public Task<PackingList?> GetPackingListByOdpNumberAsync(string odpNumber)
    {
        var plan = _context.MainPlans.SingleOrDefault(x => x.Number.ToUpper()==odpNumber.ToUpper() && x.IsDeleted==false);
        return GetPackingListByIdAsync(plan.Id);
    }

    #endregion

    #region PackingItem
    public Task<IQueryable<PackingItem>> GetPackingItemsAsync()
    {
        return Task.FromResult(_context.PackingItems.AsQueryable());
    }

    public Task<PackingItem?> GetPackingItemByIdAsync(Guid id)
    {
        return _context.PackingItems.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }

    public Task<IQueryable<PackingItem>> GetPackingItemsByMainPlanIdAsync(Guid mainPlanId)
    {
        return Task.FromResult(_context.PackingItems.Where(x => 
            x.IsDeleted==false &&  
            x.MainPlanId.Equals(mainPlanId)));
    }
    #endregion

    #region Pallet
    public Task<IQueryable<Pallet>> GetPalletsAsync()
    {
        return Task.FromResult(_context.Pallets.AsQueryable());
    }

    public Task<Pallet?> GetPalletByIdAsync(Guid id)
    {
        return _context.Pallets.SingleOrDefaultAsync(x => x.Id.Equals(id));
    }

    public Task<Pallet?> GetPalletByPalletNumber(Guid mainPlanId, int palletNumber)
    {
        return _context.Pallets.SingleOrDefaultAsync(x => x.MainPlanId.Equals(mainPlanId) && x.PalletNumber.Equals(palletNumber));
    }


    public Task<IQueryable<Pallet>> GetPalletsByMainPlanIdAsync(Guid mainPlanId)
    {
        return Task.FromResult(_context.Pallets.Where(x => 
            x.IsDeleted==false &&  
            x.MainPlanId.Equals(mainPlanId)));
    }

    public Task<bool> HavePalletAsync(Guid mainPlanId)
    {
        return Task.FromResult(_context.Pallets.Any(x => x.MainPlanId.Equals(mainPlanId)&& x.IsDeleted==false));
    }
    #endregion

    #region FinishedGoodsCount 仓库成品信息
    public Task<IQueryable<FinishedGoodsCount>> GetFinishedGoodsCountsAsync()
    {
        return Task.FromResult(_context.FinishedGoodsCounts.AsQueryable());
    }

    public Task<FinishedGoodsCount?> GetFinishedGoodsCountByIdAsync(Guid id)
    {
        return _context.FinishedGoodsCounts.SingleOrDefaultAsync(x => 
            x.Id.Equals(id) && 
            x.IsDeleted==false);
    }

    #endregion
}